package controller

import (
	"crypto/md5"
	"crypto/rand"
	"errors"
	"fmt"

	"fairysunny.com/gin-example/model"
	"fairysunny.com/gin-example/util"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

func getCurrentUser(session sessions.Session) gin.H {
	id := session.Get("user-id")
	if id == nil {
		return nil
	}
	return gin.H{
		"id":       session.Get("user-id").(int),
		"username": session.Get("user-name").(string),
		"role":     session.Get("user-role").(int),
	}
}

func hash(str string) string {
	return fmt.Sprintf("%x", md5.Sum([]byte(str)))
}

func createPassword(password string) string {
	rnd := make([]byte, 16)
	if _, err := rand.Read(rnd); err != nil {
		panic(err)
	}
	salt := fmt.Sprintf("%x", rnd)
	return salt + hash(salt+password+salt)
}

func checkPassword(password string, data string) bool {
	salt := data[:32]
	return hash(salt+password+salt) == data[32:]
}

func GetLoginStatus(c *gin.Context) {
	session := sessions.Default(c)
	util.ResOK(c, gin.H{"user": getCurrentUser(session)})
}

func Login(c *gin.Context) {
	var form struct {
		Username string `json:"username" binding:"min=1,max=30"`
		Password string `json:"password" binding:"min=1,max=30"`
	}
	if err := c.ShouldBindJSON(&form); err != nil {
		util.ResParamErr(c, err.Error())
		return
	}
	user := model.User{Username: form.Username}
	result := model.DB.Where(&user).Take(&user)
	if err := result.Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			util.ResErr(c, "用户名或密码错误")
		} else {
			util.ResSysErr(c, err.Error())
		}
		return
	}
	if !checkPassword(form.Password, user.Password) {
		util.ResErr(c, "用户名或密码错误")
		return
	}
	session := sessions.Default(c)
	session.Set("user-id", user.ID)
	session.Set("user-name", user.Username)
	session.Set("user-role", user.Role)
	if err := session.Save(); err != nil {
		util.ResSysErr(c, err.Error())
		return
	}
	util.ResOK(c, gin.H{"user": getCurrentUser(session)})
}

func Register(c *gin.Context) {
	var form struct {
		Username string `json:"username" binding:"min=1,max=30"`
		Password string `json:"password" binding:"min=1,max=30"`
	}
	if err := c.ShouldBindJSON(&form); err != nil {
		util.ResParamErr(c, err.Error())
		return
	}
	user := model.User{Username: form.Username}
	result := model.DB.Where(&user).Take(&user)
	if err := result.Error; err != nil {
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			util.ResSysErr(c, err.Error())
			return
		}
	} else {
		util.ResErr(c, "用户名已存在")
		return
	}
	user.Password = createPassword(form.Password)
	user.Role = 1
	result = model.DB.Create(&user)
	if err := result.Error; err != nil {
		util.ResSysErr(c, err.Error())
		return
	}
	session := sessions.Default(c)
	session.Set("user-id", user.ID)
	session.Set("user-name", user.Username)
	session.Set("user-role", user.Role)
	if err := session.Save(); err != nil {
		util.ResSysErr(c, err.Error())
		return
	}
	util.ResOK(c, gin.H{"user": getCurrentUser(session)})
}

func Logout(c *gin.Context) {
	session := sessions.Default(c)
	session.Delete("user-id")
	session.Delete("user-name")
	session.Delete("user-role")
	if err := session.Save(); err != nil {
		util.ResSysErr(c, err.Error())
		return
	}
	util.ResOK(c, gin.H{})
}
